package behavior

import (
	"bytes"
	"encoding/json"
	"log"
	"time"

	"xp/lib/etc"
	"xp/lib/jsonx"
	"xp/lib/md"
	"xp/lib/mux"
)

type Behavior struct {
	ReqID      string     `json:"req_id"`
	Handler    string     `json:"handler"`
	Service    string     `json:"service"`
	Revision   string     `json:"revision"`
	Host       string     `json:"host"`
	Port       int        `json:"port,string"`
	Request    []byte     `json:"request"`
	Response   []byte     `json:"response"`
	Stacktrace []byte     `json:"stacktrace"`
	CreatedOn  jsonx.Time `json:"created_on,string"`
	RecordedOn jsonx.Time `json:"recorded_on,string"`
}

func (b *Behavior) Dump() {
	if len(b.Response) == 0 {
		return
	}
	var buffer = new(bytes.Buffer)
	json.Indent(buffer, b.Response, "", "  ")
	log.Println(buffer.String())
}

func record(ctx *mux.Ctx) {
	b := &Behavior{
		ReqID:      ctx.ReqID(),
		Handler:    ctx.Name(),
		Host:       md.GetHost(),
		Port:       md.Get().Host.Port,
		Service:    md.GetService(),
		Stacktrace: ctx.GetStacktrace(),
		Revision:   md.Get().VersionControl.Revision,
		CreatedOn:  jsonx.Time(ctx.Time()),
		RecordedOn: jsonx.Time(time.Now()),
	}
	var buf bytes.Buffer
	ctx.DumpResp(&buf)
	b.Response = buf.Bytes()

	var req bytes.Buffer
	if bytes.Contains(ctx.GetHeader("Content-Type"), []byte("multipart/form-data")) {
		log.Println("reset body...")
		ctx.Request.ResetBody()
	}
	if _, err := ctx.Request.WriteTo(&req); err != nil {
		log.Println("trying dump request error:", err)
	}
	b.Request = req.Bytes()

	if etc.ModeDev() {
		b.Dump()
	}

	if err := json.NewEncoder(writer).Encode(b); err != nil {
		log.Println("trying write behavior error:", err)
	}
}

func Recorder(next mux.Handler) mux.Handler {
	return func(ctx *mux.Ctx) {
		next(ctx)
		record(ctx)
	}
}
